<?php
namespace Todo\Model\Sys;

class FilesModel extends SysBaseModel
{
    /**
     * 文件上传
     * @param  array  $files   要上传的文件列表（通常是$_FILES数组）
     * @param  array  $setting 文件上传配置
     * @param  string $driver  上传驱动名称
     * @param  array  $config  上传驱动配置
     * @return array           文件上传成功后的信息
     */
    public function upload($files, $setting, $driver = 'Local', $config = null){
        /* 上传文件 */
        $setting['callback'] = array($this, 'isFile');
        $setting['removeTrash'] = array($this, 'removeTrash');
        $Upload = new Upload($setting, $driver, $config);
        $info    = $Upload->upload($files);

        /* 设置文件保存位置 */
        $this->_auto[] = array('location', 'ftp' === strtolower($driver) ? 1 : 0, self::MODEL_INSERT);

        if($info){ //文件上传成功，记录文件信息
            foreach ($info as $key => &$value) {
                /* 已经存在文件记录 */
                if(isset($value['id']) && is_numeric($value['id'])){
                    continue;
                }
                if(strtolower($driver) != 'local'){
                    $value['sourceFile'] =$value['url'];
                } else {
                    $value['sourceFile'] = $value['savepath'].$value['savename']; //在模板里的url路径
                }
                $value['driver'] = strtolower($driver);

                /* 记录文件信息 */
                if(C('FILE_UPLOAD.autoSave') && $this->create($value) && ($id = $this->add())){
                    $value['id'] = $id;
                }
            }
            return $info; //文件上传成功
        } else {
            $this->error = $Upload->getError();
            return false;
        }
    }

    /**
     * 下载指定文件
     * @param  number  $root 文件存储根目录
     * @param  integer $id   文件ID
     * @param  string   $args     回调函数参数
     * @return boolean       false-下载失败，否则输出下载文件
     */
    public function download($root, $id, $callback = null, $args = null){
        /* 获取下载文件信息 */
        $file = $this->find($id);
        if(!$file){
            $this->error = '不存在该文件！';
            return false;
        }

        /* 下载文件 */
        switch ($file['location']) {
            case 0: //下载本地文件
                $file['rootPath'] = $root;
                return $this->downLocalFile($file, $callback, $args);
            default:
                $this->error = '不支持的文件存储类型！';
                return false;

        }

    }

    /**
     * 检测当前上传的文件是否已经存在
     * @param  array   $file 文件上传数组
     * @return boolean       文件信息， false - 不存在该文件
     */
    public function isFile($file){
        if(empty($file['md5'])){
            throw new \Exception('缺少参数:md5');
        }
        /* 查找文件 */
        $map = array('md5' => $file['md5'],'sha1'=>$file['sha1'],);
        return $this->field(true)->where($map)->find();
    }

    /**
     * 下载本地文件
     * @param  array    $file     文件信息数组
     * @param  callable $callback 下载回调函数，一般用于增加下载次数
     * @param  string   $args     回调函数参数
     * @return boolean            下载失败返回false
     */
    private function downLocalFile($file, $callback = null, $args = null){
        if(is_file($file['rootPath'].$file['sourceFile'])){
            /* 调用回调函数新增下载数 */
            is_callable($callback) && call_user_func($callback, $args);

            /* 执行下载 */ //TODO: 大文件断点续传
            header("Content-Description: File Transfer");
            header('Content-type: ' . $file['type']);
            header('Content-Length:' . $file['size']);
            if (preg_match('/MSIE/', $_SERVER['HTTP_USER_AGENT'])) { //for IE
                header('Content-Disposition: attachment; filename="' . rawurlencode($file['name']) . '"');
            } else {
                header('Content-Disposition: attachment; filename="' . $file['name'] . '"');
            }
            readfile($file['rootPath'].$file['sourceFile']);
            exit;
        } else {
            $this->error = '文件已被删除！';
            return false;
        }
    }

    /**
     * 清除数据库存在但本地不存在的数据
     * @param $data
     */
    public function removeTrash($data){
        $fsId = $data['fsId'];
        if(!empty($fsId)) {
            $fsModel = new FilesSystemModel();
            $fsModel->where(array('id'=>$fsId))->delete();
        }
        $this->where(array('id'=>$data['id'],))->delete();
    }

    /**
     * 资源文件默认上传之后保存在临时文件夹，需要在保存资源信息后，将资源文件转移到包目录下
     * @param $resId
     * @param $fileId
     */
    public function moveResFile($resId, $fileId)
    {
        $uploadPath = APP_PATH.'../'.C('FILE_UPLOAD.rootPath');
        $tempPath = C('FILE_UPLOAD.tempPath');
        $fileInfo = $this->find($fileId);
        if(substr($fileInfo['sourceFile'],0,5) != $tempPath) return;

        $folder = 'res/'. sprintf('%03d',($resId/500)+1).'/'.$resId.'/';
        if(file_exists($uploadPath.$folder) || mkdir($uploadPath.$folder,0755,true))
        {
            $fileName = $folder.substr($fileInfo['sourceFile'],5);
            if(rename($uploadPath.$fileInfo['sourceFile'], $uploadPath.$fileName))
            {
                $this->where(array('id'=>$fileId))->save(array('sourceFile'=>$fileName));
            }
        }
    }

    /**
     * 取得文件的后缀
     *
     * @param string $filename 文件名
     *
     * @return boolean
     */
    public function getExt($filename) {
        $pathinfo = pathinfo($filename);
        return strtolower($pathinfo['extension']);
    }

    protected function _before_insert(&$data,$options) {
        $fileSysConfig = C('DB_FILE_SYSTEM_CONFIG');
        if(empty($fileSysConfig)) {
            return;
        }
        // 写入资源信息表
        $fsModel = new FilesSystemModel();

        //检查fileSystem表是否存在文件
        $file = $fsModel->isFile($data);
        if($file) {
            $data['sourceFile'] = $file['sourceFile'];
            $data['tempFile'] = $file['tempFile'];
            $data['destFile'] = $file['destFile'];
            $data['preFile'] = $file['preFile'];
            //$data['htmlFile'] = $file['htmlFile'];
            $data['photo'] = $file['photo'];
            $data['status'] = $file['status'];
            $data['addTime'] =  $file['addTime'];

            $fsId = $file['id'];
        }
        else {
            $fsModel->create($data);
            $fsId = $fsModel->add();
        }
        $data['fsId'] = $fsId;
    }

    /**
     * 根据图片源地址读取图片完整的链接地址
     * @param string    $sourceFile     图片存储路径
     * @param string    $defaultPicName 默认封面名称
     * @return string
     */
    public function getImageSrc($sourceFile, $defaultPicName = 'null.gif')
    {
        if(empty($defaultPicName)) $defaultPicName = 'null.gif';
        if(empty($sourceFile)) {
            return $this->getDefaultPicUrl($defaultPicName);
        }
        $path = C('FILE_UPLOAD.rootPath').$sourceFile;
        if(!is_file($path)) {
            return $this->getDefaultPicUrl($defaultPicName);
        }
        $sourcePath = $this->getOriginalUrl($sourceFile);
        return $sourcePath;
    }

    /**
     * 根据图片ID读取图片信息
     * @param int    $fileId 文件ID
     * @param string $defaultPicName 默认封面名称
     * @param string $field  字段名称
     * @return String  完整的数据  或者  指定的$field字段值
     */
    public function getImage($fileId, $defaultPicName = 'null.gif', $field = null)
    {
        if(empty($fileId)) {
            return array('path' => $this->getDefaultPicUrl($defaultPicName));
        }
        $fileInfo = $this->where(array('id' => $fileId))->find();
        if(empty($fileInfo)) {
            return array('path' => $this->getDefaultPicUrl($defaultPicName));
        }
        if(!empty($fileInfo) && (empty($field) || 'path' === $field)) {
            $fileInfo['path'] = $this->getImageSrc($fileInfo['sourceFile'], $defaultPicName);
        }
        return empty($field) ? $fileInfo : $fileInfo[$field];
    }

    /**
     * 根据文件路径读取图片网络地址.
     * @param string    $sourceFile     图片存储路径
     * @return string
     */
    protected  function getOriginalUrl($sourceFile) {
        return __UPLOAD__.'/'.$sourceFile;
    }

    /**
     * 根据默认图片名称读取默认图片地址.
     * @param string    $defaultPicName    默认图片名称
     * @return string
     */
    protected  function getDefaultPicUrl($defaultPicName) {
        return __STATIC__.'/images/'.$defaultPicName;
    }
}